//
//  BookingsManager.m
//  mUBB
//
//  Created by Cosmin Stirbu on 3/3/13.
//  Copyright (c) 2013 Cosmin Stirbu. All rights reserved.
//

#import "BookingsManager.h"
#import "WSManager+Bookings.h"
#import "Constants.h"
#import "UserDefaultsManager.h"


@implementation BookingsManager

// Singleton
+ (BookingsManager *)instance
{
    static BookingsManager *instance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[BookingsManager alloc] init];
        // Do any other initialisation stuff here
    });
    return instance;
}

- (Ticket *)getBookingsForCourse:(Course *)course delegate:(id<BookingsProtocol>)delegate {
    return [[WSManager instance] getBookingsForCourse:course delegate:delegate];
}

- (Ticket *)getBookingsForRoom:(Room *)room withDate:(NSDate *)date delegate:(id<BookingsProtocol>)delegate {
    return [[WSManager instance] getBookingsForRoom:room withDate:date delegate:delegate];
}

- (Ticket *)createBooking:(Booking *)booking delegate:(id<BookingsProtocol>)delegate {
    return [[WSManager instance] createBooking:booking delegate:delegate];
}

- (Ticket *)updateBooking:(Booking *)booking delegate:(id<BookingsProtocol>)delegate {
    return [[WSManager instance] updateBooking:booking delegate:delegate];
}

- (Ticket *)deleteBooking:(Booking *)booking delegate:(id<BookingsProtocol>)delegate {
    return [[WSManager instance] deleteBooking:booking delegate:delegate];
}

- (NSDictionary *)groupBookingsByTypeOfClass:(NSArray *)bookings {
    NSMutableDictionary *groupedBookings = [NSMutableDictionary new];
    for (Booking *booking in bookings) {
        NSArray *typesOfClasses = [groupedBookings allKeys];
        TypeOfClass *typeOfClass = booking.typeOfClass;
        if ([booking.typeOfClass isOtherType]) {
            // It is another type of class
            typeOfClass = [TypeOfClass new];
            typeOfClass.typeOfClassId = TypeOfClass_Other;
            typeOfClass.name = NSLocalizedString(@"TYPE_OF_CLASS_OTHER", nil);
        }
        // Check if the type of class is not already in the dictionary
        if (![typesOfClasses containsObject:typeOfClass]) {
                NSMutableArray *bookingsForTypeOfClass = [NSMutableArray new];
                [bookingsForTypeOfClass addObject:booking];
                [groupedBookings setObject:bookingsForTypeOfClass forKey:typeOfClass];
            } else {
                // Small hack, objectForKey method uses hash method so when we use object for key we need to use the same key with which the object was added
                typeOfClass = [typesOfClasses objectAtIndex:[typesOfClasses indexOfObject:typeOfClass]];
                // The type of class is already in the dictionary
                NSMutableArray *bookingsForTypeOfClass = [groupedBookings objectForKey:typeOfClass];
                [bookingsForTypeOfClass addObject:booking];
            }
    }
    return groupedBookings;
}

- (NSArray *)sortTypesOfClasses:(NSDictionary *)groupedBookings {
    NSArray *typesOfClasses = [groupedBookings allKeys];
    return [typesOfClasses sortedArrayUsingComparator:^NSComparisonResult(id a, id b) {
        NSInteger typeOfClass1 = [(TypeOfClass *)a typeOfClassId];
        NSInteger typeOfClass2 = [(TypeOfClass *)b typeOfClassId];
        if (typeOfClass1 < typeOfClass2)
            return NSOrderedAscending;
        if (typeOfClass1 > typeOfClass2)
            return NSOrderedDescending;
        return NSOrderedSame;
    }];
}

- (BOOL)bookingsStillAvailable:(NSArray *)bookings {
    NSDate *todayDate = [NSDate date];
    for (Booking *booking in bookings) {
        if ([booking.startDate compare:todayDate] == NSOrderedDescending && ![self bookingIsInCalendar:booking])
            return YES;
    }
    return NO;
}

- (BOOL)bookingIsInCalendar:(Booking *)booking {
    return [UserDefaultsManager getObjectForKey:[NSString stringWithFormat:@"%d", booking.bookingId]] != nil;
}

- (void)saveIdentifier:(EKEvent *)event forBooking:(Booking *)booking {
    [UserDefaultsManager saveObject:event.eventIdentifier forKey:[NSString stringWithFormat:@"%d", booking.bookingId]];
}

- (NSInteger)addAllFutureEventsToCalendar:(NSArray *)bookings {
    EKEventStore *es = [[EKEventStore alloc] init];
    if ([es respondsToSelector:@selector(requestAccessToEntityType:completion:)]) {
        // IOS 6
        [es requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error) {
            /* This code will run when uses has made his/her choice */
            if (granted) {
                // Add Booking
                 [self addBookingsToCalendar:bookings];
            }
        }];
    } else {
        // Add Bookings
        [self addBookingsToCalendar:bookings];
    }
    return [self numberOfBookingsToAdd:bookings];
}

- (NSInteger)numberOfBookingsToAdd:(NSArray *)bookings  {
    NSDate *todayDate = [NSDate date];
    NSInteger numberOfBookings = 0;
    for (Booking *booking in bookings) {
        if ([booking.startDate compare:todayDate] == NSOrderedDescending && ![self bookingIsInCalendar:booking]) {
            numberOfBookings ++;
        }
    }
    return numberOfBookings;
}

- (void)addBookingsToCalendar:(NSArray *)bookings {
    NSDate *todayDate = [NSDate date];
    for (Booking *booking in bookings) {
        if ([booking.startDate compare:todayDate] == NSOrderedDescending && ![self bookingIsInCalendar:booking]) {
            EKEventStore *eventStore = [[EKEventStore alloc] init];
            EKEvent *event  = [EKEvent eventWithEventStore:eventStore];
            // Title
            event.title = [NSString stringWithFormat:@"%@ (%@)", booking.course.courseName, booking.typeOfClass.name];
            
            // Start Date
            event.startDate = booking.startDate;
            event.endDate = booking.endDate;
            
            // Teacher + Study groups
            event.notes = [NSString stringWithFormat:@"%@ %@\n%@", booking.teacher.firstName, booking.teacher.lastName, [self stringWithBookingStudyGroups:booking.studyGroups]];
            
            // Location
            event.location = [NSString stringWithFormat:@"%@, %@", booking.room.name, booking.room.building.name];
            
            [event setCalendar:[eventStore defaultCalendarForNewEvents]];
            
            NSError *err = nil;
            [eventStore saveEvent:event span:EKSpanThisEvent error:&err];
            
            if (err == nil) {
                // Boooking was added successfully
                [self saveIdentifier:event forBooking:booking];
            }
            
        }
    }
}

- (NSString *)stringWithBookingStudyGroups:(NSArray *)studyGroups {
    NSMutableString *string = [NSMutableString string];
    for (StudyGroup *studyGroup in studyGroups) {
        [string appendFormat:@"%@,", studyGroup.name];
    }
    if ([string length] > 1) {
        return [string substringToIndex:[string length] - 1];
    }
    return nil;
}

- (void)deleteBookingFromCalendar:(Booking *)booking {
    NSString *eventIdentifier = [UserDefaultsManager getObjectForKey:[NSString stringWithFormat:@"%d", booking.bookingId]];
    if (![NSString isNullOrEmpty:eventIdentifier]) {
        // The booking is in the calendar
        EKEventStore* store = [EKEventStore new];
        EKEvent* eventToRemove = [store eventWithIdentifier:eventIdentifier];
        NSError* error = nil;
        [store removeEvent:eventToRemove span:EKSpanThisEvent error:&error];
        [UserDefaultsManager removeObjectForKey:[NSString stringWithFormat:@"%d", booking.bookingId]];
    }
}

@end
